package org.chen.newsapi.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.Getter;
import lombok.Setter;
import org.chen.newsapi.common.Result;
import org.chen.newsapi.entity.Article;
import org.chen.newsapi.mapper.ArticleMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

@RestController
@RequestMapping("/apis/view")
public class ArticleViewController {

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // Redis key 前缀
    private static final String VIEW_COUNT_CACHE_PREFIX = "article:view:count:";
    private static final String IP_LAST_VIEW_PREFIX = "article:ip:lastview:";

    // 定时任务执行器
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    public ArticleViewController() {
        // 每30秒批量更新数据库
        scheduler.scheduleAtFixedRate(this::flushViewCountToDatabase, 30, 30, TimeUnit.SECONDS);
    }

    /**
     * 增加文章浏览量 - 带防刷机制
     */
    @PostMapping("/articles/{id}/view")
    public Result<String> increaseViewCount(@PathVariable String id, 
                                           @RequestParam(required = false) String clientIp) {
        try {
            // 基本验证
            if (id == null || id.trim().isEmpty()) {
                return Result.error("文章ID不能为空");
            }

            // 验证文章是否存在
            Article article = articleMapper.selectById(id);
            if (article == null) {
                return Result.error("文章不存在");
            }

            // 防刷机制：同一IP在5分钟内只能增加一次浏览量
            String ipKey = clientIp != null ? clientIp : "unknown";
            String ipCacheKey = IP_LAST_VIEW_PREFIX + id + "_" + ipKey;

            // 检查上次访问时间
            Object lastViewTimeObj = redisTemplate.opsForValue().get(ipCacheKey);
            long currentTime = System.currentTimeMillis();

            if (lastViewTimeObj != null) {
                long lastViewTime = Long.parseLong(lastViewTimeObj.toString());
                if ((currentTime - lastViewTime) < 5 * 60 * 1000) {
                    // 5分钟内重复访问，不增加浏览量但返回成功
                    return Result.error("浏览量已记录");
                }
            }

            // 记录访问时间（24小时过期）
            redisTemplate.opsForValue().set(ipCacheKey, currentTime, 24, TimeUnit.HOURS);

            // 增加Redis中的浏览量计数
            String viewCountKey = VIEW_COUNT_CACHE_PREFIX + id;
            redisTemplate.opsForValue().increment(viewCountKey, 1);
            // 设置过期时间（7天）
            redisTemplate.expire(viewCountKey, 7, TimeUnit.DAYS);

            return Result.success("浏览量增加成功");
        } catch (Exception e) {
            return Result.error("增加浏览量失败：" + e.getMessage());
        }
    }

    /**
     * 批量增加文章浏览量
     */
    @PostMapping("/articles/batch-view")
    public Result<String> batchIncreaseViewCount(@RequestBody BatchViewRequest request,
                                                 @RequestParam(required = false) String clientIp) {
        try {
            if (request.getArticleIds() == null || request.getArticleIds().isEmpty()) {
                return Result.error("文章ID列表不能为空");
            }

            String ipKey = clientIp != null ? clientIp : "unknown";
            long currentTime = System.currentTimeMillis();

            int successCount = 0;
            for (String articleId : request.getArticleIds()) {
                String ipCacheKey = IP_LAST_VIEW_PREFIX + articleId + "_" + ipKey;

                // 检查防刷
                Object lastViewTimeObj = redisTemplate.opsForValue().get(ipCacheKey);
                boolean canIncrement = true;

                if (lastViewTimeObj != null) {
                    long lastViewTime = Long.parseLong(lastViewTimeObj.toString());
                    if ((currentTime - lastViewTime) < 5 * 60 * 1000) {
                        canIncrement = false;
                    }
                }

                if (canIncrement) {
                    // 验证文章存在
                    Article article = articleMapper.selectById(articleId);
                    if (article != null) {
                        // 记录访问时间
                        redisTemplate.opsForValue().set(ipCacheKey, currentTime, 24, TimeUnit.HOURS);

                        // 增加浏览量
                        String viewCountKey = VIEW_COUNT_CACHE_PREFIX + articleId;
                        redisTemplate.opsForValue().increment(viewCountKey, 1);
                        redisTemplate.expire(viewCountKey, 7, TimeUnit.DAYS);

                        successCount++;
                    }
                }
            }

            return Result.success("批量处理完成，成功处理 " + successCount + " 篇文章");
        } catch (Exception e) {
            return Result.error("批量处理失败：" + e.getMessage());
        }
    }

    /**
     * 获取文章当前浏览量
     */
    @GetMapping("/articles/{id}/count")
    public Result<Long> getViewCount(@PathVariable String id) {
        try {
            Article article = articleMapper.selectById(id);
            if (article == null) {
                return Result.error("文章不存在");
            }

            // 当前数据库中的浏览量
            long dbCount = article.getViewCount() != null ? article.getViewCount() : 0;

            // Redis缓存中的增量
            String viewCountKey = VIEW_COUNT_CACHE_PREFIX + id;
            Object cacheCountObj = redisTemplate.opsForValue().get(viewCountKey);
            long cacheCount = cacheCountObj != null ? Long.parseLong(cacheCountObj.toString()) : 0;

            return Result.success(dbCount + cacheCount);
        } catch (Exception e) {
            return Result.error("获取浏览量失败：" + e.getMessage());
        }
    }

    /**
     * 批量获取文章浏览量
     */
    @PostMapping("/articles/batch-count")
    public Result<Map<String, Long>> getBatchViewCount(@RequestBody BatchViewRequest request) {
        try {
            Map<String, Long> result = new ConcurrentHashMap<>();

            for (String articleId : request.getArticleIds()) {
                Article article = articleMapper.selectById(articleId);
                if (article != null) {
                    long dbCount = article.getViewCount() != null ? article.getViewCount() : 0;

                    // 获取Redis中的缓存计数
                    String viewCountKey = VIEW_COUNT_CACHE_PREFIX + articleId;
                    Object cacheCountObj = redisTemplate.opsForValue().get(viewCountKey);
                    long cacheCount = cacheCountObj != null ? Long.parseLong(cacheCountObj.toString()) : 0;

                    result.put(articleId, dbCount + cacheCount);
                }
            }

            return Result.success(result);
        } catch (Exception e) {
            return Result.error("批量获取浏览量失败：" + e.getMessage());
        }
    }

    /**
     * 将Redis缓存中的浏览量刷新到数据库
     */
    private void flushViewCountToDatabase() {
        try {
            // 获取所有浏览量缓存的key
            Set<String> keys = redisTemplate.keys(VIEW_COUNT_CACHE_PREFIX + "*");
            if (keys.isEmpty()) {
                return;
            }

            for (String key : keys) {
                try {
                    // 提取文章ID
                    String articleId = key.substring(VIEW_COUNT_CACHE_PREFIX.length());

                    // 获取并删除Redis中的计数（原子操作）
                    Object countObj = redisTemplate.opsForValue().getAndDelete(key);
                    if (countObj != null) {
                        long incrementCount = Long.parseLong(countObj.toString());

                        if (incrementCount > 0) {
                            // 更新数据库
                            Article article = articleMapper.selectById(articleId);
                            if (article != null) {
                                long newViewCount = (article.getViewCount() != null ? article.getViewCount() : 0) + incrementCount;
                                article.setViewCount(newViewCount);
                                articleMapper.updateById(article);
                            }
                        }
                    }
                } catch (Exception e) {
                    // 单个文章处理失败不影响其他文章
                    System.err.println("处理文章浏览量失败，key: " + key + ", 错误: " + e.getMessage());
                }
            }

        } catch (Exception e) {
            // 记录错误，但不影响定时任务继续执行
            System.err.println("刷新浏览量到数据库失败：" + e.getMessage());
        }
    }

    /**
     * 手动刷新浏览量到数据库（管理员接口）
     */
    @PostMapping("/flush")
    public Result<String> manualFlush() {
        try {
            flushViewCountToDatabase();
            return Result.success("浏览量已刷新到数据库");
        } catch (Exception e) {
            return Result.error("刷新失败：" + e.getMessage());
        }
    }

    /**
     * 清理过期的缓存数据（管理员接口）
     */
    @PostMapping("/cleanup")
    public Result<String> cleanupCache() {
        try {
            // Redis的过期机制会自动清理过期数据，这里主要是手动触发清理
            Set<String> ipKeys = redisTemplate.keys(IP_LAST_VIEW_PREFIX + "*");
            if (!ipKeys.isEmpty()) {
                long currentTime = System.currentTimeMillis();
                int cleanupCount = 0;

                for (String key : ipKeys) {
                    Object timeObj = redisTemplate.opsForValue().get(key);
                    if (timeObj != null) {
                        long lastTime = Long.parseLong(timeObj.toString());
                        // 清理24小时前的记录
                        if ((currentTime - lastTime) > 24 * 60 * 60 * 1000) {
                            redisTemplate.delete(key);
                            cleanupCount++;
                        }
                    }
                }

                return Result.success("清理完成，删除了 " + cleanupCount + " 条过期记录");
            }

            return Result.success("没有需要清理的过期记录");
        } catch (Exception e) {
            return Result.error("清理失败：" + e.getMessage());
        }
    }

    /**
     * 获取缓存统计信息（管理员接口）
     */
    @GetMapping("/cache-stats")
    public Result<Map<String, Object>> getCacheStats() {
        try {
            Map<String, Object> stats = new ConcurrentHashMap<>();

            Set<String> viewCountKeys = redisTemplate.keys(VIEW_COUNT_CACHE_PREFIX + "*");
            Set<String> ipKeys = redisTemplate.keys(IP_LAST_VIEW_PREFIX + "*");

            stats.put("pendingViewCounts", viewCountKeys.size());
            stats.put("ipRecords", ipKeys.size());

            // 统计待刷新的总浏览量
            long totalPendingViews = 0;
            for (String key : viewCountKeys) {
                Object countObj = redisTemplate.opsForValue().get(key);
                if (countObj != null) {
                    totalPendingViews += Long.parseLong(countObj.toString());
                }
            }
            stats.put("totalPendingViews", totalPendingViews);

            return Result.success(stats);
        } catch (Exception e) {
            return Result.error("获取缓存统计失败：" + e.getMessage());
        }
    }

    // 批量浏览量请求类
    @Setter
    @Getter
    public static class BatchViewRequest {
        private List<String> articleIds;

    }
}